package com.lmind.core.publish;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;


public abstract class AbstractPublisher<P> {

	protected ConcurrentHashMap<String, ConcurrentHashMap<Subscriber<P>, String>> subscribers = new ConcurrentHashMap<String, ConcurrentHashMap<Subscriber<P>, String>>();

	private ConcurrentHashMap<Subscriber<P>, String> backup = new ConcurrentHashMap<Subscriber<P>, String>();

	protected synchronized boolean containsName(String name) {
		return subscribers.containsKey(name);
	}
	
	/**
	 * 获取一个订阅者的所有订阅的信息
	 * @param subscriber 订阅者
	 * @return 所有订阅的信息
	 */
	protected synchronized List<String> namesBySubscriber(Subscriber<P> subscriber) {
		ArrayList<String> list = new ArrayList<String>();
		for (ConcurrentHashMap<Subscriber<P>, String> set : subscribers.values()) {
			String name = set.get(subscriber);
			if (name != null)
				list.add(name);
		}
		return list;
	}
	
	protected void doPublish(String name, P pub) {
		if (pub == null || name == null)
			throw new IllegalArgumentException("参数不可以是null");
		
		ConcurrentHashMap<Subscriber<P>,String> set = subscribers.get(name);
		if (set == null)
			return;
		for (Subscriber<P> subscriber : set.keySet()) {
			subscriber.feed(name, pub);
		}
	}

	protected synchronized void doSubscribe(Subscriber<P> subscriber,
			String name) {
		if (subscriber == null || name == null)
			throw new IllegalArgumentException("参数不可以是null");

		ConcurrentHashMap<Subscriber<P>, String> set = subscribers.putIfAbsent(
				name, backup);
		if (set == null) {
			set = backup;
			backup = new ConcurrentHashMap<Subscriber<P>, String>();
		}

		if (set.putIfAbsent(subscriber, name) != null) {
			throw new SubscribeException("不可重复订阅");
		}
	}

	protected synchronized void doUnsubscribe(Subscriber<P> subscriber,
			String name) {
		if (subscriber == null || name == null)
			throw new IllegalArgumentException("参数不可以是null");
		
		ConcurrentHashMap<Subscriber<P>, String> set = subscribers.get(name);
		if (set == null || set.remove(subscriber) == null)
			throw new SubscribeException("该订阅者尚未订阅当前信息");
		if (set.size() == 0) {
			subscribers.remove(name);
		}
	}

	protected synchronized void doCleanSubscribe(Subscriber<P> subscriber) {

		Iterator<ConcurrentHashMap<Subscriber<P>, String>> iter = subscribers
				.values().iterator();
		while (iter.hasNext()) {
			ConcurrentHashMap<Subscriber<P>, String> set = iter.next();
			set.remove(subscriber);
			if (set.size() == 0) {
				iter.remove();
			}
		}
	}
}
